﻿using System;
using System.Linq;
using CommonBehaviors.Actions;
using FarmerJoe.Helpers;
using FarmerJoe.Helpers.Units;
using FarmerJoe.Settings;
using Styx;
using Styx.CommonBot;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using Action = Styx.TreeSharp.Action;

namespace FarmerJoe.Classes
{
    public static partial class Warlock
    {
        private static LocalPlayer Me { get { return StyxWoW.Me; } }
        private static WoWUnit CT { get { return Me.CurrentTarget; } }
        public delegate int SimpleIntegerDelegate(object context);

        #region Specialisation Switchs
        // Determine which routine to use based on your specialisation
        //
        public static Composite CombatBehavior_SpecSwitch()
        {
            return new PrioritySelector(

                new Switch<WoWSpec>(ret => Me.Specialization,
                                                 new SwitchArgument<WoWSpec>(WoWSpec.WarlockAffliction, CombatBehavior_Afflication),
                                                 new SwitchArgument<WoWSpec>(WoWSpec.None, CombatBehavior_LowLevel),
                                                 new SwitchArgument<WoWSpec>(WoWSpec.WarlockDemonology, CombatBehavior_Demonology),
                                                 new SwitchArgument<WoWSpec>(WoWSpec.WarlockDestruction, CombatBehavior_Destruction)
                ));
        }

        public static Composite PullBehavior_SpecSwitch()
        {
            return new PrioritySelector(

                new Switch<WoWSpec>(ret => Me.Specialization,
                                                 new SwitchArgument<WoWSpec>(WoWSpec.WarlockAffliction, PullBehavior_Afflication),
                                                 new SwitchArgument<WoWSpec>(WoWSpec.None, CombatBehavior_LowLevel),
                                                 new SwitchArgument<WoWSpec>(WoWSpec.WarlockDemonology, PullBehavior_Demonology),
                                                 new SwitchArgument<WoWSpec>(WoWSpec.WarlockDestruction, PullBehavior_Destruction)
                ));
        }
        #endregion


        public static WoWUnit DoTAddTarget(string spellName)
        {

            foreach (WoWUnit unit in ObjectManager.GetObjectsOfType<WoWUnit>(false,false))
            {
                if (unit.Distance2DSqr > 40 * 40) continue;
                if (unit.HealthPercent < 30 && !unit.Elite) continue;
                if (!unit.InLineOfSpellSight) continue;
                if (!Extensions.ValidUnit(unit)) continue;
                if (!unit.IsTargetingMeOrPet && !unit.IsTargetingMyPartyMember && !unit.IsTargetingMyRaidMember && !unit.Aggro && !unit.PetAggro) continue;
                if (unit.AuraTimeLeft(spellName) > 3) continue;
                

                if (!unit.HasMyAura(spellName)) return unit;
            }

            return null;
        }

        public static int CountOfMyCurses
        {
            get
            {
                int result = 0;

                result += CT.HasMyAura("Corruption") ? 1 : 0;
                result += CT.HasMyAura("Agony") ? 1 : 0;
                result += CT.HasMyAura("Unstable Affliction") ? 1 : 0;
                
                return result;
            }

        }

        public static bool NotCursed
        {
            get { return !CT.HasMyAura("Curse of the Elements") && !CT.HasMyAura("Curse of Enfeeblement") && !CT.HasMyAura("Curse of Exhaustion"); }
        }

        public static WoWUnit FearedMob
        {
            get { return Targeting.Instance.TargetList.FirstOrDefault(unit => unit.HasMyAura("Fear") || unit.HasMyAura("Blood Fear")); }
        }

        public static WoWUnit MobToFear
        {
            get
            {
                //foreach (WoWUnit unit in Targeting.Instance.TargetList)
                foreach (WoWUnit unit in ObjectManager.GetObjectsOfType<WoWUnit>(false,false))
                {
                    if (unit.Distance2DSqr > 30 * 30) continue;
                    if (!unit.IsTargetingMeOrPet && !unit.IsTargetingMyPartyMember && !unit.IsTargetingMyRaidMember && !unit.Aggro && !unit.PetAggro) continue;
                    if (unit.Guid == CT.Guid) continue;
                    if (!unit.InLineOfSpellSight) continue;
                    if (unit.IsTargetingMeOrPet) return unit;
                    
                }
                return null;
            }
        }

        private static WoWUnit _soulburnSoulSwapTarget = null;
        public static WoWUnit DoTAddTargetSoulBurnSoulSwap
        {
            get
            {

                if (!Timers.AutoExpire("Soulburn soul sawp target", 1000) && _soulburnSoulSwapTarget != null && _soulburnSoulSwapTarget.IsValid) return _soulburnSoulSwapTarget;

                foreach (WoWUnit unit in ObjectManager.GetObjectsOfType<WoWUnit>(false,false))
                {
                    if (unit.Distance2DSqr > 40 * 40) continue;
                    if (!unit.IsTargetingMeOrPet && !unit.IsTargetingMyPartyMember && !unit.IsTargetingMyRaidMember && !unit.Aggro && !unit.PetAggro) continue;
                    if (unit.HealthPercent < 40 && !unit.Elite) continue;
                    if (!unit.InLineOfSpellSight) continue;
                    if (!Extensions.ValidUnit(unit)) continue;
                    if (unit.AuraTimeLeft("Corruption") > 3 && unit.AuraTimeLeft("Agony") > 3 && unit.AuraTimeLeft("Unstable Afflication") > 3) continue;
                    
                    if (Me.GotTarget && unit.Guid == Me.CurrentTargetGuid) continue;

                    _soulburnSoulSwapTarget = unit;
                    return _soulburnSoulSwapTarget;
                }
                return null;
            }
        }

        private static bool NeedHealthStone
        {
            get
            {
                bool haveItem = false;
                foreach (WoWItem item in StyxWoW.Me.CarriedItems)
                {
                    if (item.ItemSpells.Any(s => s.ActualSpell != null && s.ActualSpell.Name == "Healthstone"))
                    {
                        haveItem = true;
                        break;
                    }
                }

                //Log.Write(Colours.InformativeColour,"===== do we have a healthstone? " + haveItem);
                return !haveItem;
            }
        }

        public static Composite DrainLife()
        {
            Helpers.Logging.Log.Write("===================== wtf ");
            return new PrioritySelector(
                    new Decorator(ret => IsCastingOK && Me.GotTarget,
                        new Sequence(
                            new DecoratorContinue(ret => Me.Specialization == WoWSpec.WarlockAffliction && !Me.HasAura("Soulburn") && CLC.ResultOK(FpswareSettings.Instance.Warlock.AfflictionDrainLifeSoulburn) && Me.GetCurrentPower(WoWPowerType.SoulShards) >= Convert.ToInt32(FpswareSettings.Instance.Warlock.AfflictionDrainLifeSoulburnMinShards),
                                new Sequence(
                                    Spells.Buff("Soulburn", ret => Me, ret => !Me.HasAura("Soulburn"), false),
                                    new WaitContinue(2, ret => Me.HasAura("Soulburn"), new ActionAlwaysSucceed())
                                    )
                                ),

                            new Sequence(
                                new DecoratorContinue(ret => !Me.IsSafelyFacing(CT,55),
                                    new Sequence(
                                        new Action(context => CT.Face()),
                                        new WaitContinue(2, ret => false, new ActionAlwaysSucceed())
                                        )
                                )
                            ),

                            new Decorator(ret => CT.Distance <= 40,
                                new Sequence(
                                    Spells.Cast("Drain Life")
                                )
                            )
                        ))
                );
        }


        // Healing. Based on current specialisation
        public static Composite AllFormsHeal()
        {
            return new PrioritySelector(

                Spells.BuffSelf("Unbound Will", ret => Me.Combat && Me.IsCrowdControlled()),
                Spells.BuffSelf("Dark Intent", ret => !Me.ActiveAuras.ContainsKey("Dark Intent") && FpswareSettings.Instance.Warlock.DarkIntent.Contains("always")),


                new Decorator(ret => Me.Specialization == WoWSpec.WarlockAffliction,
                              new PrioritySelector(
                                  new Decorator(ret => !FpswareSettings.Instance.Warlock.AfflictionDarkBargin.Contains("never") && CLC.ResultOK(FpswareSettings.Instance.Warlock.AfflictionDarkBarginWhen),
                                    new PrioritySelector(
                                        Spells.Cast("Dark Bargin", ret => Me.HealthPercent <= FpswareSettings.Instance.Warlock.AfflictionDarkBarginHealth)
                                        )),
                                  Spells.Cast("Unending Resolve", ret => Me.HealthPercent <= FpswareSettings.Instance.Warlock.AfflictionUnendingResolveHealth),
                                  Spells.Cast("Dark Regeneration", ret => Me.HealthPercent <= FpswareSettings.Instance.Warlock.AfflictionDarkRegenerationHealth),
                
                                  // Drain Life. But first check if we need to face the target
                                  new Decorator(ret => Me.HealthPercent <= FpswareSettings.Instance.Warlock.AfflictionDrainLifeHealth && Me.GotTarget && Me.Combat,
                                       new Sequence(
                                         new DecoratorContinue(ret => !Me.IsSafelyFacing(CT, 45),
                                            new Sequence(
                                                new Action(context => CT.Face()),
                                                new WaitContinue(2, ret => false, new ActionAlwaysSucceed())
                                                )),

                                        Spells.Cast("Drain Life", ret => Me.HealthPercent <= FpswareSettings.Instance.Warlock.AfflictionDrainLifeHealth)
                                    ))
                                  

                                  )),


                new Decorator(ret => Me.Specialization == WoWSpec.WarlockDemonology,
                              new PrioritySelector(
                                    new Decorator(ret => !FpswareSettings.Instance.Warlock.DemoDarkBargin.Contains("never") && CLC.ResultOK(FpswareSettings.Instance.Warlock.DemoDarkBarginWhen),
                                        new PrioritySelector(

                                            Spells.Cast("Dark Bargin", ret => Me.HealthPercent <= FpswareSettings.Instance.Warlock.DemoDarkBarginHealth)
                                            )),

                                 Spells.Cast("Dark Regeneration", ret => Me.HealthPercent <= FpswareSettings.Instance.Warlock.DemoDarkRegenerationHealth),
                                //Spells.Cast("Mortal Coil", ret => Me.HealthPercent <= FpswareSettings.Instance.Warlock.DemoMortalCoilHealth),
                                Spells.Cast("Unending Resolve", ret => Me.HealthPercent <= FpswareSettings.Instance.Warlock.DemoUnendingResolveHealth),

                                // Drain Life. But first check if we need to face the target
                                  new Decorator(ret => Me.HealthPercent <= FpswareSettings.Instance.Warlock.DemoDrainLifeHealth && Me.GotTarget,
                                       new Sequence(
                                         new DecoratorContinue(ret => !Me.IsSafelyFacing(CT, 45),
                                            new Sequence(
                                                new Action(context => CT.Face()),
                                                new WaitContinue(2, ret => false, new ActionAlwaysSucceed())
                                                )),

                                        Spells.Cast("Drain Life", ret => Me.HealthPercent <= FpswareSettings.Instance.Warlock.DemoDrainLifeHealth)
                                    ))

                                  )),


                new Decorator(
                    ret => Me.Specialization == WoWSpec.WarlockDestruction || Me.Specialization == WoWSpec.None,
                    new PrioritySelector(
                        
                        new Decorator( ret => !FpswareSettings.Instance.Warlock.DestructionDarkBargin.Contains("never") && CLC.ResultOK(FpswareSettings.Instance.Warlock.DestructionDarkBarginWhen),
                            new PrioritySelector(
                                Spells.Cast("Dark Bargin", ret => Me.HealthPercent <= FpswareSettings.Instance.Warlock.DestructionDarkBarginHealth)
                                )),

                        Spells.Cast("Ember Tap", ret => Me.HealthPercent <= FpswareSettings.Instance.Warlock.EmberTabHealth && Me.GetCurrentPower(WoWPowerType.BurningEmbers) >= 10),
                        //Spells.Cast("Mortal Coil", ret => Me.HealthPercent <= FpswareSettings.Instance.Warlock.MortalCoilHealth),
                        Spells.Cast("Unending Resolve", ret => Me.HealthPercent <= FpswareSettings.Instance.Warlock.UnendingResolveHealth),
                        Spells.Cast("Dark Regeneration", ret => Me.HealthPercent <= FpswareSettings.Instance.Warlock.DestructionDarkRegenerationHealth),

                        // Drain Life. But first check if we need to face the target
                                  new Decorator(ret => Me.HealthPercent <= FpswareSettings.Instance.Warlock.DrainLifeHealth && Me.GotTarget,
                                       new Sequence(
                                         new DecoratorContinue(ret => !Me.IsSafelyFacing(CT, 45),
                                            new Sequence(
                                                new Action(context => CT.Face()),
                                                new WaitContinue(2, ret => false, new ActionAlwaysSucceed())
                                                )),

                                        Spells.Cast("Drain Life", ret => Me.HealthPercent <= FpswareSettings.Instance.Warlock.DrainLifeHealth)
                                    ))
                        

                        
                         
                                
                                
                )));
        }

        public static Composite AllFormsRest()
        {
            return new PrioritySelector(
                
                Spells.WaitForCast(),

                SummonPet(),
                Spells.BuffSelf("Create Healthstone", ret=> NeedHealthStone && !Me.IsCasting && Timers.AutoExpire("Create Healthstone",5000)),
                Spells.BuffSelf("Dark Intent", ret => !Me.ActiveAuras.ContainsKey("Dark Intent") && FpswareSettings.Instance.Warlock.DarkIntent.Contains("always")),

                new Decorator(ret => Me.Specialization == WoWSpec.WarlockAffliction,
                    new PrioritySelector(
                        new Decorator(ret => FpswareSettings.Instance.Warlock.AfflictionSoulLink.Contains("always") && WoWSpell.FromId(108415).CanCast && Me.GotAlivePet && !Me.Auras.ContainsKey("Soul Link"),
                            new Action(r => SpellManager.Cast("Soul Link")))

                        )),

                        new Decorator(ret => Me.Specialization == WoWSpec.WarlockDestruction,
                    new PrioritySelector(
                        new Decorator(ret => FpswareSettings.Instance.Warlock.DestructionSoulLink.Contains("always") && WoWSpell.FromId(108415).CanCast && Me.GotAlivePet && !Me.Auras.ContainsKey("Soul Link"),
                            new Action(r => SpellManager.Cast("Soul Link")))

                        )),

                new Decorator(ret => Me.Specialization == WoWSpec.WarlockDemonology,
                    new PrioritySelector(

                        // Life Tap
                        new Decorator(ret => !FpswareSettings.Instance.Warlock.DemoLifeTap.Contains("never") && Me.HealthPercent > FpswareSettings.Instance.Warlock.DemoLifeTapMinHealth && Me.ManaPercent < FpswareSettings.Instance.Warlock.DemoLifeTapMana,
                            new Sequence(
                                Spells.Cast("Life Tap"),
                                new WaitContinue(2, ret => !SpellManager.GlobalCooldown, new ActionAlwaysSucceed())
                                )),

                        // Soul Link
                        new Decorator(ret => FpswareSettings.Instance.Warlock.DemoSoulLink.Contains("always") && Me.GotAlivePet && !Me.Auras.ContainsKey("Soul Link") && WoWSpell.FromId(108415).CanCast,
                            new Action(r => SpellManager.Cast("Soul Link"))),
                            //new Action(r => Spells.LUACast("Soul Link"))),

                        // Remove Soul Link
                        new Decorator(ret => FpswareSettings.Instance.Warlock.DemoSoulLink.Contains("never") && Me.HasAura("Soul Link"),
                            new Action(r => Lua.DoString("CancelUnitBuff('player', 'Soul Link')")))

                )),

                Spells.BuffSelf("Unending Breath", ret => !Me.HasAura("Unending Breath") && Me.IsSwimming),

                
                new Decorator(ret => Me.IsCasting || Me.IsChanneling || SpellManager.GlobalCooldown, new Action(context => RunStatus.Success)),
                
                // Base common behaviour
                Common.RestBehaviour()
                
                );
        }

        // Used by all specs
        public static Composite PreCombatBuffs()
        {
            return new PrioritySelector(

                Spells.WaitForCast(),
                SummonPet(),

                new Decorator(ret => Me.Specialization == WoWSpec.WarlockDemonology,
                    new PrioritySelector(
                        
                        // Soul Link
                        new Decorator(ret => FpswareSettings.Instance.Warlock.DemoSoulLink.Contains("always") && Me.GotAlivePet && !Me.HasAura("Soul Link") && WoWSpell.FromId(108415).CanCast,
                            new Action(r => Spells.LUACast("Soul Link")))

                )),

                 
                AllFormsHeal(),

                Spells.BuffSelf("Dark Intent", ret=> !Me.ActiveAuras.ContainsKey("Dark Intent") && FpswareSettings.Instance.Warlock.DarkIntent.Contains("always")),

                new Decorator(ret => Me.IsCasting || Me.IsChanneling, new Action(context => RunStatus.Success))

                );
        }

        public static Composite SummonPet()
        {
            return new Decorator(ret=> !Me.GotAlivePet && !Me.Mounted && !Me.IsFlying && Timers.SpellOkToCast("Summon Pet") && !Me.HasAura("Food") && !Me.HasAura("Drink") && !Me.HasAura("Grimoire of Sacrifice") &&  !Me.IsCasting,
                new PrioritySelector(

                     // Low Level
                    new Decorator(ret => Me.Specialization == WoWSpec.None,
                        new Sequence(
                            new Action(ret => SpellManager.Cast("Summon Imp")),
                            Spells.WaitForLagDuration(),
                            new Action(ret => Timers.Reset("Summon Pet")),
                            new Wait(5, ret => StyxWoW.Me.GotAlivePet || !StyxWoW.Me.IsCasting,
                                new PrioritySelector(
                                    new Decorator(ret => StyxWoW.Me.IsCasting,
                                        new Action(ret => SpellManager.StopCasting())),
                                        new ActionAlwaysSucceed()))
                    )),



                    // Demonology
                    new Decorator(ret=> Me.Specialization == WoWSpec.WarlockDemonology && !FpswareSettings.Instance.Warlock.DemoSummonPet.Contains("none"),
                        new Sequence(
                            new Action(ret=> SpellManager.Cast("Summon " + FpswareSettings.Instance.Warlock.DemoSummonPet)),
                            Spells.WaitForLagDuration(),
                            new Action(ret=> Timers.Reset("Summon Pet")),
                            new Wait(5, ret => StyxWoW.Me.GotAlivePet || !StyxWoW.Me.IsCasting,
                                new PrioritySelector(
                                    new Decorator(ret => StyxWoW.Me.IsCasting,
                                        new Action(ret => SpellManager.StopCasting())),
                                        new ActionAlwaysSucceed()))
                    )),

                    // Demonology
                    new Decorator(ret => Me.Specialization == WoWSpec.WarlockDestruction && !FpswareSettings.Instance.Warlock.DestructionSummonPet.Contains("none"),
                        new Sequence(
                            new Action(ret => SpellManager.Cast("Summon " + FpswareSettings.Instance.Warlock.DestructionSummonPet)),
                            Spells.WaitForLagDuration(),
                            new Action(ret => Timers.Reset("Summon Pet")),
                            new Wait(5, ret => StyxWoW.Me.GotAlivePet || !StyxWoW.Me.IsCasting,
                                new PrioritySelector(
                                    new Decorator(ret => StyxWoW.Me.IsCasting,
                                        new Action(ret => SpellManager.StopCasting())),
                                        new ActionAlwaysSucceed()))
                    )),

                    // Affliction
                     new Decorator(ret=> Me.Specialization == WoWSpec.WarlockAffliction && !FpswareSettings.Instance.Warlock.AfflictionSummonPet.Contains("none"),
                         new Sequence(

                             // Soulburn summon?
                             new DecoratorContinue(ret => !Me.HasAura("Soulburn") && Me.CurrentSoulShards >=1 && CLC.ResultOK(FpswareSettings.Instance.Warlock.AfflictionSoulburnSummon),
                                new Sequence(
                                    Spells.Buff("Soulburn", ret => Me, ret => !Me.HasAura("Soulburn"), false),
                                    new WaitContinue(2, ret => Me.HasAura("Soulburn"), new ActionAlwaysSucceed())
                                    )),

                            // Summon the pet
                            new Sequence(
                                new Action(ret=> SpellManager.Cast("Summon " + FpswareSettings.Instance.Warlock.AfflictionSummonPet)),
                                Spells.WaitForLagDuration(),
                                new Action(ret=> Timers.Reset("Summon Pet")),
                                new Wait(5, ret => StyxWoW.Me.GotAlivePet || !StyxWoW.Me.IsCasting,
                                    new PrioritySelector(
                                        new Decorator(ret => StyxWoW.Me.IsCasting,
                                            new Action(ret => SpellManager.StopCasting())),
                                            new ActionAlwaysSucceed()))
                    )))
                    
                    )
                    
                    
                    
                    
                    );
        }

        public static Composite CommandDemon()
        {
            return new Decorator(
                new PrioritySelector(
                    
                    
                    
                    ));
        }

        public static Composite PetSpells()
        {
            return new Decorator(ret=> Me.GotAlivePet,
                new PrioritySelector(

                    new Decorator(ret => Pets.CurrentPetType == Pets.PetType.WrathGuard || Pets.CurrentPetType == Pets.PetType.Felguard,
                        new PrioritySelector(
                            new Decorator(ret=> CLC.ResultOK(FpswareSettings.Instance.Warlock.PetAxeToss) && Pets.CanCastPetAction("Axe Toss"), new Action(context => Pets.CastPetAction("Axe Toss"))),
                            new Decorator(ret=> CLC.CountOfMobs(FpswareSettings.Instance.Warlock.PetWrathStorm,8, Me.Pet) && Pets.CanCastPetAction("Wrathstorm"), new Action(context => Pets.CastPetAction("Wrathstorm"))),
                            new Decorator(ret=> CLC.ResultOK(FpswareSettings.Instance.Warlock.PetWrathStorm) && Pets.CanCastPetAction("Felstorm"), new Action(context => Pets.CastPetAction("Felstorm")))
                            )
                    
                    ),
                    
                    new Decorator(ret => Pets.CurrentPetType == Pets.PetType.FelImp || Pets.CurrentPetType == Pets.PetType.Imp,
                        new Decorator(ret=> CLC.ResultOK(FpswareSettings.Instance.Warlock.PetCauterizeMaster) && Me.HealthPercent < FpswareSettings.Instance.Warlock.PetCauterizeMasterHealth && Pets.CanCastPetAction("Cauterize Master"),
                            new Action(context => Pets.CastPetAction("Cauterize Master")))
                    ),

                    new Decorator(ret => Pets.CurrentPetType == Pets.PetType.Succubus || Pets.CurrentPetType == Pets.PetType.Shivarra,
                        new Decorator(ret => CLC.ResultOK(FpswareSettings.Instance.Warlock.PetWhiplash) && Pets.CanCastPetAction("Whiplash"),
                            new Sequence(
                                new Action(context => Pets.CastPetAction("Whiplash")),
                                new WaitContinue(1, ret => Me.HasPendingSpell("Whiplash"), new ActionAlwaysSucceed()),
                                new Action(context => SpellManager.ClickRemoteLocation(CT.Location)),
                                new WaitContinue(1, ret => false, new ActionAlwaysSucceed())
                                )
                            )
                    ),

                    new Decorator(ret => Pets.CurrentPetType == Pets.PetType.Felhunter || Pets.CurrentPetType == Pets.PetType.Observer,
                        new Decorator(ret => CLC.ResultOK(FpswareSettings.Instance.Warlock.PetSpellLock) && Pets.CanCastPetAction("Spell Lock"),
                            new Action(context => Pets.CastPetAction("Spell Lock")))
                    )

                    
                            
                            
                            ));
        }



    }
}
